home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 46
/
Amiga Format CD46 (1999-10-20)(Future Publishing)(GB)[!][issue 1999-12].iso
/
-in_the_mag-
/
reader_requests
/
pdflib
/
p_basic.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-09-16
|
13KB
|
527 lines
/* p_basic.c
* Copyright (C) 1997-98 Thomas Merz. All rights reserved.
*
* PDFlib general routines
*/
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "p_intern.h"
/*
* The names arrays must be kept in sync with the corresponding
* enum types in pdf.h
*/
const char *pdf_filter_names[compression_count] = {
"", "LZWDecode", "RunLengthDecode", "CCITTFaxDecode",
"DCTDecode", "FlateDecode"
};
const char *pdf_colorspace_names[colorspace_count] = {
"DeviceGray", "DeviceRGB", "DeviceCMYK",
"CalGray", "CalRGB", "Lab",
"Indexed", "Pattern", "Separation"
};
const char *pdf_transition_names[] = {
"", "Split", "Blinds", "Box", "Wipe", "Dissolve", "Glitter", "R"
};
void
pdf_default_error_handler(int level, const char* fmt, va_list ap)
{
switch (level) {
case PDF_INFO:
fprintf(stderr, "PDFlib note: ");
vfprintf(stderr, fmt, ap);
fputc('\n', stderr);
break;
case PDF_WARN:
fprintf(stderr, "PDFlib warning: ");
vfprintf(stderr, fmt, ap);
fputc('\n', stderr);
break;
case PDF_INTERNAL:
fprintf(stderr, "PDFlib internal error: ");
vfprintf(stderr, fmt, ap);
fputc('\n', stderr);
exit(88);
break;
case PDF_FATAL:
default:
fprintf(stderr, "PDFlib fatal error: ");
vfprintf(stderr, fmt, ap);
fputc('\n', stderr);
exit(99);
}
}
void
pdf_error(PDF *p, int level, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
(*p->info->error_handler)(level, fmt, ap);
va_end(ap);
}
void *
PDF_malloc(size_t size, char *caller)
{
void *ret;
if ((ret = calloc(size, 1)) == NULL) {
fprintf(stderr, "PDFLIB: couldn't allocate memory in %s!\n", caller);
}
return ret;
}
void
PDF_free(void *mem)
{
free(mem);
}
PDF_info*
PDF_get_info(void)
{
PDF_info *info;
info = (PDF_info *) PDF_malloc(sizeof(PDF_info), "PDF_get_info");
info->binary_mode = false;
info->required_compatibility= PDF1_1;
/* Info dictionary entries */
info->Keywords = NULL;
info->Subject = NULL;
info->ModDate = NULL;
info->Title = NULL;
info->CreationDate = NULL;
info->Creator = NULL;
info->Producer = NULL;
info->Author = NULL;
info->error_handler = pdf_default_error_handler;
info->fontpath = PDF_DEFAULT_FONT_PATH;
return info;
}
PDF *
PDF_open(FILE *fp, PDF_info *info)
{
time_t timer;
struct tm ltime;
PDF *p;
if (info == NULL)
return (PDF *) NULL;
if ((p = (PDF *) PDF_malloc(sizeof(PDF), "PDF_open")) == NULL)
return (PDF *) NULL;
p->fp = fp;
p->info = info;
#ifdef DEBUG
/* We override the caller's option for debugging! */
p->info->binary_mode = true;
#endif
if (ftell(p->fp) == -1)
pdf_error(p, PDF_FATAL, "Problem with PDF output file!");
(void) fputs("%PDF-1.1\n", p->fp); /* Header */
/* write binary magic number for ASCII and binary files! */
(void) fputs("%\342\343\317\323\n", p->fp);
p->info_id = pdf_begin_obj(p, NEW_ID); /* Info object */
pdf_begin_dict(p);
if(p->info->Keywords)
(void) fprintf(p->fp, "/Keywords (%s)\n", p->info->Keywords);
if(p->info->Subject)
(void) fprintf(p->fp, "/Subject (%s)\n", p->info->Subject);
if(p->info->Title)
(void) fprintf(p->fp, "/Title (%s)\n", p->info->Title);
if(p->info->Creator)
(void) fprintf(p->fp, "/Creator (%s)\n", p->info->Creator);
if(p->info->Author)
(void) fprintf(p->fp, "/Author (%s)\n", p->info->Author);
time(&timer);
ltime = *localtime(&timer);
(void) fprintf(p->fp, "/CreationDate (D:%04d%02d%02d%02d%02d%02d)\n",
ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday,
ltime.tm_hour, ltime.tm_min, ltime.tm_sec);
(void) fprintf(p->fp,"/Producer (%s)\n", PDFLIB_VERSION);
pdf_end_dict(p);
pdf_end_obj(p);
p->current_page = 0;
p->outlines_id = 0;
p->pages_id = pdf_alloc_id(p);
p->root_id = pdf_alloc_id(p);
p->open_outlines = 0;
p->image_number = 0;
p->outline_count = 0;
/* HACK, should use font cache */
p->current_font = (pdf_font *) PDF_malloc(sizeof(pdf_font), "PDF_open");
return p;
}
/* separate finalize routine requested by Just van Rossum
* for supporting the Python binding
*/
void
pdf_finalize(PDF *p)
{
fclose(p->fp);
/* HACK, should use font cache */
PDF_free((void *)p->current_font);
PDF_free((void *)p->info);
PDF_free((void *)p);
/* TODO: free item list */
}
void
PDF_close(PDF *p)
{
long pos;
int page;
id i;
if (p->current_page == 0 ) { /* avoid empty document */
PDF_begin_page(p, 100.0, 100.0); /* arbitrary page size */
PDF_end_page(p);
pdf_error(p, PDF_WARN, "Empty document!");
}
p->open_action = pdf_begin_obj(p, NEW_ID);
(void) fprintf(p->fp,"[ %ld 0 R /Fit ]\n", p->pages[1]);
pdf_end_obj(p);
pdf_put_fonts(p); /* Font objects */
pdf_begin_obj(p, p->pages_id); /* root Pages object */
pdf_begin_dict(p);
(void) fputs("/Type /Pages\n", p->fp);
(void) fprintf(p->fp,"/Count %d\n", p->current_page);
(void) fputs("/Kids [", p->fp);
for (page = 1; page <= p->current_page; page++) {
(void) fprintf(p->fp,"%ld 0 R", p->pages[page]);
(void) fputs(page % 6 ? " " : "\n", p->fp);
}
(void) fputs("]\n", p->fp);
pdf_end_dict(p);
pdf_end_obj(p);
pdf_begin_obj(p, p->root_id); /* Catalog or Root object */
pdf_begin_dict(p);
(void) fputs("/Type /Catalog\n", p->fp);
/* make the first page fit in the window */
(void) fprintf(p->fp,"/OpenAction %ld 0 R\n", p->open_action);
/* open outlines if the document has any */
if (p->outline_count > 0)
(void) fputs("/PageMode /UseOutlines\n", p->fp);
/* Pages object */
(void) fprintf(p->fp,"/Pages %ld 0 R\n", p->pages_id);
if (p->outlines_id != 0)
(void) fprintf(p->fp,"/Outlines %ld 0 R\n", p->outlines_id);
pdf_end_dict(p);
pdf_end_obj(p);
pdf_write_outlines(p);
/* don't write any objects after this check! */
for (i = 1; i <= p->currentobj; i++) {
if (p->file_offset[i] == BAD_ID) {
pdf_error(p, PDF_WARN,
"Object %ld allocated but not used (dummy inserted)!", i);
pdf_begin_obj(p, i);
pdf_end_obj(p);
}
}
pos = ftell(p->fp); /* xref table */
(void) fputs("xref\n", p->fp);
(void) fprintf(p->fp,"0 %ld\n", p->currentobj + 1);
(void) fputs("0000000000 65535 f \n", p->fp);
for (i = 1; i <= p->currentobj; i++) {
(void) fprintf(p->fp,"%010ld 00000 n \n", p->file_offset[i]);
#ifdef FOOBAR
(void) fprintf(p->fp,"%010ld 00000 n\n", p->file_offset[i]);
#endif
}
(void) fputs("trailer\n", p->fp);
pdf_begin_dict(p);
(void) fprintf(p->fp,"/Size %ld\n", p->currentobj + 1);
(void) fprintf(p->fp,"/Info %ld 0 R\n", p->info_id);
(void) fprintf(p->fp,"/Root %ld 0 R\n", p->root_id);
pdf_end_dict(p);
(void) fputs("startxref\n", p->fp);
(void) fprintf(p->fp,"%ld\n", pos);
(void) fputs("%%EOF\n", p->fp);
pdf_finalize(p);
}
void
pdf_begin_contents_section(PDF *p)
{
if (p->contents != c_none)
return;
if (p->next_content > MAX_CONTENTS)
pdf_error(p, PDF_FATAL, "Too many content sections on page (%ld)!",
p->contents);
/* Contents object */
p->contents_ids[p->next_content] = pdf_begin_obj(p, NEW_ID);
p->contents = c_stream;
pdf_begin_dict(p);
p->contents_length = pdf_alloc_id(p);
(void) fprintf(p->fp,"/Length %ld 0 R\n", p->contents_length);
pdf_end_dict(p);
pdf_begin_stream(p);
p->start_contents_pos = ftell(p->fp);
p->next_content++;
}
void
pdf_end_contents_section(PDF *p)
{
long length;
if (p->contents == c_none)
return;
pdf_end_text(p);
p->contents = c_none;
length = ftell(p->fp) - p->start_contents_pos;
pdf_end_stream(p);
pdf_end_obj(p);
pdf_begin_obj(p, p->contents_length); /* Length object */
(void) fprintf(p->fp,"%ld\n", length);
pdf_end_obj(p);
}
void
PDF_begin_page(PDF *p, float height, float width)
{
if (++(p->current_page) > MAX_PAGES)
pdf_error(p, PDF_FATAL, "Too many pages in document (%d)!",
p->current_page);
p->pages[p->current_page] = pdf_alloc_id(p);
p->height = height;
p->width = width;
p->next_content = 0;
p->contents = c_none;
pdf_begin_contents_section(p);
}
void
PDF_end_page(PDF *p)
{
pdf_item *i;
int index = 0;
pdf_end_contents_section(p);
pdf_begin_obj(p, p->pages[p->current_page]); /* Page object */
pdf_begin_dict(p);
(void) fputs("/Type /Page\n", p->fp);
(void) fprintf(p->fp,"/Parent %ld 0 R\n", p->pages_id);
p->res_id = pdf_alloc_id(p);
(void) fprintf(p->fp,"/Resources %ld 0 R\n", p->res_id);
(void) fprintf(p->fp,"/MediaBox [0 0 %g %g]\n", p->height, p->width);
if (p->duration > 0)
(void) fprintf(p->fp, "/D %s\n", pdf_float(p->duration));
if (p->transition != trans_none) {
(void) fputs("/Trans ", p->fp);
pdf_begin_dict(p);
(void) fprintf(p->fp, "/S /%s",
pdf_transition_names[p->transition]);
pdf_end_dict(p);
}
(void) fputs("/Contents [", p->fp);
for (index = 0; index < p->next_content; index++) {
(void) fprintf(p->fp,"%ld 0 R", p->contents_ids[index]);
(void) fputs(index+1 % 6 ? " " : "\n", p->fp);
}
(void) fputs("]\n", p->fp);
pdf_end_dict(p);
pdf_end_obj(p);
pdf_begin_obj(p, p->res_id); /* Resource object */
pdf_begin_dict(p);
(void) fputs("/ProcSet [/PDF", p->fp); /* ProcSet resources */
if ( p->res.procset & ImageB)
(void) fputs(" /ImageB", p->fp);
if ( p->res.procset & ImageC)
(void) fputs(" /ImageC", p->fp);
if ( p->res.procset & ImageI)
(void) fputs(" /ImageI", p->fp);
if ( p->res.procset & Text)
(void) fputs(" /Text", p->fp);
(void) fputs("]\n", p->fp);
if (p->res.font != (pdf_item *) NULL)
{
(void) fputs("/Font ", p->fp); /* Font resources */
pdf_begin_dict(p);
for(i = p->res.font, index = 0; i != (pdf_item *) NULL; i = i->next)
{
(void) fprintf(p->fp,"/F%d %ld 0 R\n", index++, i->obj_id);
}
pdf_end_dict(p);
}
if (p->res.xobject != (pdf_item *) NULL)
{
(void) fputs("/XObject ", p->fp); /* XObject resources */
pdf_begin_dict(p);
for(i = p->res.xobject, index = 0; i != (pdf_item *) NULL; i = i->next)
{
(void) fprintf(p->fp,"/I%d %ld 0 R\n", index++, i->obj_id);
}
pdf_end_dict(p);
}
pdf_end_dict(p);
pdf_end_obj(p);
}
/* set page display duration for current and future pages */
void
PDF_set_duration(PDF *p, float t)
{
p->duration = t;
}
/* set transition mode for current and future page */
void
PDF_set_transition(PDF *p, PDF_transition t)
{
if (t >= transition_count) {
pdf_error(p, PDF_WARN, "Illegal page transition value");
return;
}
p->transition = t;
}
id
pdf_begin_obj(PDF *p, id obj_id)
{
if (obj_id == NEW_ID)
obj_id = pdf_alloc_id(p);
p->file_offset[obj_id] = ftell(p->fp);
(void) fprintf(p->fp, "%ld 0 obj\n", obj_id);
return obj_id;
}
id
pdf_alloc_id(PDF *p)
{
p->currentobj++;
if (p->currentobj >= MAX_ID)
pdf_error(p, PDF_FATAL, "Too many objects (%ld)!", p->currentobj);
/* only needed for verifying obj table in PDF_close() */
p->file_offset[p->currentobj] = BAD_ID;
return p->currentobj;
}
pdf_item *
pdf_add_res_font(PDF *p, char *basename)
{
pdf_item *item, **last_item;
last_item = &p->res.font;
for (item = p->res.font; item != (pdf_item *) NULL; item = item->next)
{
if (!strcmp(item->basename, basename))
return item; /* resource already listed */
last_item = &item->next;
}
*last_item = (pdf_item *) PDF_malloc(sizeof(pdf_item), "pdf_add_res_font");
item = *last_item;
item->name = (char *) PDF_malloc(6, "pdf_add_res_font");
sprintf(item->name, "/F%d", p->font_number);
p->font_number++;
item->basename= (char *) PDF_malloc(strlen(basename)+1, "pdf_add_res_font");
strcpy(item->basename, basename);
item->obj_id = pdf_alloc_id(p);
item->next = (pdf_item *) NULL;
*last_item = item;
return item;
}
void
pdf_add_res_xobject(PDF *p, id xobj_id)
{
pdf_item *item, **last_item;
last_item = &p->res.xobject;
for (item = p->res.xobject; item != (pdf_item *) NULL; item = item->next)
last_item = &item->next;
*last_item = (pdf_item *) PDF_malloc(sizeof(pdf_item), "pdf_add_res_xobject");
item = *last_item;
item->name = (char *) PDF_malloc(6, "pdf_add_res_xobject");
sprintf(item->name, "/I%d", p->xobject_number);
p->xobject_number++;
item->obj_id = xobj_id;
item->next = (pdf_item *) NULL;
*last_item = item;
}